package org.springblade.system.excel;

import org.springblade.common.cache.DictBizCache;
import org.springblade.common.cache.DictCache;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.modules.system.pojo.entity.Dict;
import org.springblade.modules.system.pojo.entity.DictBiz;
import org.springblade.modules.system.pojo.vo.DictBizVO;
import org.springblade.modules.system.pojo.vo.DictVO;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

public class ExcelSelectorCache {

	private static final ThreadLocal<Map<String, Map<String, Object>>> LOCAL = ThreadLocal.withInitial(HashMap::new);

	private static JdbcTemplate jdbcTemplate;


	public static final String selector = "selector";
	public static final String key2value = "key2value";
	public static final String value2key = "value2key";
	public static final String origin = "origin";
	public static final String sub = "_sub";

	public static JdbcTemplate getJdbcTemplate(){
		if (jdbcTemplate == null) {
			jdbcTemplate = SpringUtil.getBean(JdbcTemplate.class);
		}
		return jdbcTemplate;
	}

	/**
	 * 从ThreadLocal中获取值
	 *
	 * @param key 键
	 * @see Map#get(Object)
	 * @see ClassCastException
	 */
	@Nullable
	public static Map<String, Object> get(String key) {
		return LOCAL.get().computeIfAbsent(key,k->new HashMap<>());
	}

	/**
	 * 从ThreadLocal中获取值,并指定一个当值不存在的提供者
	 *
	 */
	@Nullable
	public static Map<String,Object> get(String key, Callable<Map<String,Object>> valueLoader) {

		Map<String, Object> call;
		try {
			call = valueLoader.call();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		LOCAL.get().computeIfAbsent(key, k-> call);
		return call;
	}

	/**
	 * 获取业务表的数据作为关联的key value
	 * @param key 为此业务取一个唯一的名称
	 * @param sql 必须 as key value 例如 select id as key,name as value from blade_user
	 * @return
	 */
	public static Map<String,Object> getBizCode(String key,String sql){
		return get(key, ()->{
			List<Map<String, Object>> maps = getJdbcTemplate().queryForList(sql);
			int size = maps.size();
			Map<String,Object> map = new HashMap<>();
			String[] selectorValue = new String[size];
			Map<String,String> key2valueValue = new HashMap<>();
			Map<String,String> value2keyValue = new HashMap<>();
			for (int i = 0; i < size; i++) {
				String dictKey = String.valueOf(maps.get(i).get("key"));
				String dictValue = String.valueOf(maps.get(i).get("value"));
				selectorValue[i] = dictValue;
				key2valueValue.put(dictKey, dictValue);
				value2keyValue.put(dictValue, dictKey);
			}
			map.put(selector,selectorValue);
			map.put(key2value,key2valueValue);
			map.put(value2key,value2keyValue);
			map.put(origin,maps);

			return map;
		});
	}

	public static void getSysDict(String... keys){
		for (String key : keys){
			getSysDict(key);
		}
	}
	public static Map<String,Object> getSysDict(String key) {
		return get(key, ()->{
			List<Dict> list = DictCache.getList(key);
			List<DictVO> dictVOS = buildSysVO(list);
			int size = dictVOS.size();
			Map<String,Object> map = new HashMap<>();
			String[] selectorValue = new String[size];
			Map<String,String> key2valueValue = new HashMap<>();
			Map<String,String> value2keyValue = new HashMap<>();
			for (int i = 0; i < size; i++) {
				String dictKey = dictVOS.get(i).getDictKey();
				String dictValue = dictVOS.get(i).getDictValue();
				selectorValue[i] = dictValue;
				key2valueValue.put(dictKey, dictValue);
				value2keyValue.put(dictValue, dictKey);
			}
			map.put(selector,selectorValue);
			map.put(key2value,key2valueValue);
			map.put(value2key,value2keyValue);
			map.put(origin,list);

			return map;
		});
	}
	public static void getBizDict(String... keys){
		for (String key : keys){
			getBizDict(key);
		}
	}
	public static Map<String,Object> getBizDict(String key) {
		return get(key, ()->{
			List<DictBiz> list = DictBizCache.getList(key);
			List<DictBizVO> dictBizVOS = buildVO(list);
			int size = dictBizVOS.size();
			Map<String,Object> map = new HashMap<>();
			String[] selectorValue = new String[size];
			Map<String,String> key2valueValue = new HashMap<>();
			Map<String,String> value2keyValue = new HashMap<>();
			for (int i = 0; i < size; i++) {
				String dictKey = dictBizVOS.get(i).getDictKey();
				String dictValue = dictBizVOS.get(i).getDictValue();
				selectorValue[i] = dictValue;
				key2valueValue.put(dictKey, dictValue);
				value2keyValue.put(dictValue, dictKey);
			}
			map.put(selector,selectorValue);
			map.put(key2value,key2valueValue);
			map.put(value2key,value2keyValue);
			map.put(origin,list);

			return map;
		});
	}

	public void getBizDictSub(String... keys){
		for (String key : keys){
			getBizDictSub(key);
		}
	}
	public static Map<String,Object> getBizDictSub(String key) {
		String key_sub = key+sub;
		return get(key_sub, ()->{
			List<DictBiz> list = DictBizCache.getList(key);
			List<DictBizVO> dictBizVOS = buildVO(list);
			int size = dictBizVOS.size();
			Map<String,Object> map = new HashMap<>();
			List<String> selectorValueList = new ArrayList<>();
			Map<String,String> key2valueValue = new HashMap<>();
			Map<String,String> value2keyValue = new HashMap<>();
			for (int i = 0; i < size; i++) {
				if(dictBizVOS.get(i).getChildren()!=null){
					dictBizVOS.get(i).getChildren().forEach(dictBizVO -> {
						String dictKey = dictBizVO.getDictKey();
						String dictValue = dictBizVO.getDictValue();
						selectorValueList.add(dictValue);
						key2valueValue.put(dictKey, dictValue);
						value2keyValue.put(dictValue, dictKey);
					});
				}

			}
			map.put(selector,selectorValueList.toArray(new String[0]));
			map.put(key2value,key2valueValue);
			map.put(value2key,value2keyValue);
			map.put(origin,list);

			return map;
		});
	}

	public static List<DictBizVO> buildVO(List<DictBiz> list){
		List<DictBizVO> collect = list.stream().map(dict -> BeanUtil.copy(dict, DictBizVO.class)).collect(Collectors.toList());
		return ForestNodeMerger.merge(collect);
	}

	public static List<DictVO> buildSysVO(List<Dict> list){
		List<DictVO> collect = list.stream().map(dict -> BeanUtil.copy(dict, DictVO.class)).collect(Collectors.toList());
		return ForestNodeMerger.merge(collect);
	}



	/**
	 * 设置一个值到ThreadLocal
	 *
	 * @param key   键
	 * @param value 值
	 * @return 被放入的值
	 * @see Map#put(Object, Object)
	 */
	public static Map<String, Object> put(String key, Map<String, Object> value) {
		LOCAL.get().computeIfAbsent(key,k->value);
		return value;
	}

	public static void put(String key,String bizKey, Object value) {
		Map<String, Object> stringObjectMap = LOCAL.get().computeIfAbsent(key, k -> new HashMap<>());
		stringObjectMap.put(bizKey,value);
	}


	/**
	 * 删除参数对应的值
	 *
	 * @param key
	 * @see Map#remove(Object)
	 */
	public static void remove(String key) {
		LOCAL.get().remove(key);
	}

	/**
	 * 清空ThreadLocal
	 *
	 * @see Map#clear()
	 */
	public static void clear() {
		LOCAL.remove();
	}


}
